/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.zh.harmony.lifecycle;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 缓存反射的方法信息的单例类
 */
class ClassesInfoCache {
    /**
     * 单实例
     */
    static ClassesInfoCache sInstance = new ClassesInfoCache();

    /**
     * 无形参的回调方法
     */
    private static final int CALL_TYPE_NO_ARG = 0;
    /**
     * 只有1个形参，并且形参类型为LifecycleOwner的回调方法
     */
    private static final int CALL_TYPE_PROVIDER = 1;
    /**
     * 有2个形参，并且形参类型为LifecycleOwner和Event事件类型的回调方法
     */
    private static final int CALL_TYPE_PROVIDER_WITH_EVENT = 2;

    /**
     * 回调信息缓存
     */
    private final Map<Class, CallbackInfo> mCallbackMap = new HashMap<>();
    /**
     * 是否有生命周期回调方法的缓存
     */
    private final Map<Class, Boolean> mHasLifecycleMethods = new HashMap<>();

    /**
     * 判断订阅者上是否有生命周期回调方法
     */
    boolean hasLifecycleMethods(Class klass) {
        //优先从缓存中获取，缓存中有则直接返回
        Boolean hasLifecycleMethods = mHasLifecycleMethods.get(klass);
        if (hasLifecycleMethods != null) {
            return hasLifecycleMethods;
        }
        //没有缓存，反射获取方法列表
        Method[] methods = getDeclaredMethods(klass);
        //遍历判断有没有方法加了@OnLifecycleEvent注解
        for (Method method : methods) {
            OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
            if (annotation != null) {
                // Optimization for reflection, we know that this method is called
                // when there is no generated adapter. But there are methods with @OnLifecycleEvent
                // so we know that will use ReflectiveGenericLifecycleObserver,
                // so we createInfo in advance.
                // CreateInfo always initialize mHasLifecycleMethods for a class, so we don't do it
                // here.
                //缓存回调信息
                createInfo(klass, methods);
                return true;
            }
        }
        //没有找到方法，加入缓存中
        mHasLifecycleMethods.put(klass, false);
        return false;
    }

    /**
     * 获取Class上的所有方法
     */
    private Method[] getDeclaredMethods(Class klass) {
        try {
            return klass.getDeclaredMethods();
        } catch (NoClassDefFoundError e) {
            throw new IllegalArgumentException("The observer class has some methods that use "
                    + "newer APIs which are not available in the current OS version. Lifecycles "
                    + "cannot access even other methods so you should make sure that your "
                    + "observer classes only access framework classes that are available "
                    + "in your min API level OR use lifecycle:compiler annotation processor.", e);
        }
    }

    /**
     * 获取订阅者的回调信息
     */
    CallbackInfo getInfo(Class klass) {
        CallbackInfo existing = mCallbackMap.get(klass);
        if (existing != null) {
            return existing;
        }
        existing = createInfo(klass, null);
        return existing;
    }

    /**
     * 校验
     */
    private void verifyAndPutHandler(Map<MethodReference, Lifecycle.Event> handlers,
                                     MethodReference newHandler, Lifecycle.Event newEvent, Class klass) {
        Lifecycle.Event event = handlers.get(newHandler);
        if (event != null && newEvent != event) {
            Method method = newHandler.mMethod;
            throw new IllegalArgumentException(
                    "Method " + method.getName() + " in " + klass.getName()
                            + " already declared with different @OnLifecycleEvent value: previous"
                            + " value " + event + ", new value " + newEvent);
        }
        if (event == null) {
            handlers.put(newHandler, newEvent);
        }
    }

    /**
     * 把回调方法的信息都保存到一个CallbackInfo对象中
     */
    private CallbackInfo createInfo(Class klass, Method[] declaredMethods) {
        //获取父类Class
        Class superclass = klass.getSuperclass();
        //回调方法和对应的事件Map
        Map<MethodReference, Lifecycle.Event> handlerToEvent = new HashMap<>();

        //如果有父类，获取父类上的回调方法信息
        if (superclass != null) {
            CallbackInfo superInfo = getInfo(superclass);
            //找到了，则保存起来
            if (superInfo != null) {
                handlerToEvent.putAll(superInfo.mHandlerToEvent);
            }
        }

        //获取所有接口，如果接口上有回调方法，则也加上
        Class[] interfaces = klass.getInterfaces();
        for (Class intrfc : interfaces) {
            for (Map.Entry<MethodReference, Lifecycle.Event> entry : getInfo(intrfc).mHandlerToEvent.entrySet()) {
                verifyAndPutHandler(handlerToEvent, entry.getKey(), entry.getValue(), klass);
            }
        }

        //查找类上的所有方法
        Method[] methods = declaredMethods != null ? declaredMethods : getDeclaredMethods(klass);
        boolean hasLifecycleMethods = false;
        //遍历所有方法
        for (Method method : methods) {
            //查找回调方法
            OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
            if (annotation == null) {
                //不是回调方法，找下一个
                continue;
            }
            //找到了，标记存在生命周期回调方法
            hasLifecycleMethods = true;
            //获取方法形参
            Class<?>[] params = method.getParameterTypes();
            //如果参数个数为0，则callType = CALL_TYPE_NO_ARG，method不包含入参参数
            int callType = CALL_TYPE_NO_ARG;
            //如果参数个数大于0，则第一个参数必须是LifecycleOwner类型的对象，否则抛出异常
            if (params.length > 0) {
                //如果参数个数为1，则 callType = CALL_TYPE_PROVIDER
                callType = CALL_TYPE_PROVIDER;
                if (!params[0].isAssignableFrom(LifecycleOwner.class)) {
                    throw new IllegalArgumentException(
                            "invalid parameter type. Must be one and instanceof LifecycleOwner");
                }
            }
            //获取注解值
            Lifecycle.Event event = annotation.value();
            //如果参数个数为 2，注解值必须是Lifecycle.Event类型，而注解值，必须是Lifecycle.Event.ON_ANY
            if (params.length > 1) {
                //设置callType = CALL_TYPE_PROVIDER_WITH_EVENT
                callType = CALL_TYPE_PROVIDER_WITH_EVENT;
                if (!params[1].isAssignableFrom(Lifecycle.Event.class)) {
                    throw new IllegalArgumentException(
                            "invalid parameter type. second arg must be an event");
                }
                if (event != Lifecycle.Event.ON_ANY) {
                    throw new IllegalArgumentException(
                            "Second arg is supported only for ON_ANY value");
                }
            }
            //如果参数个数大于2，则抛出异常，所以要求回调方法最多包含两个参数，且对参数类型和参数顺序进行了限制
            if (params.length > 2) {
                throw new IllegalArgumentException("cannot have more than 2 params");
            }
            //创建方法引用，回调方法时通过它来反射回调
            MethodReference methodReference = new MethodReference(callType, method);
            //校验和保存
            verifyAndPutHandler(handlerToEvent, methodReference, event, klass);
        }
        //创建回调信息
        CallbackInfo info = new CallbackInfo(handlerToEvent);
        //缓存回调信息
        mCallbackMap.put(klass, info);
        //缓存是否存在生命周期回调方法标记
        mHasLifecycleMethods.put(klass, hasLifecycleMethods);
        return info;
    }

    /**
     * 存储回调信息的类
     */
    @SuppressWarnings("WeakerAccess")
    static class CallbackInfo {
        final Map<Lifecycle.Event, List<MethodReference>> mEventToHandlers;
        final Map<MethodReference, Lifecycle.Event> mHandlerToEvent;

        CallbackInfo(Map<MethodReference, Lifecycle.Event> handlerToEvent) {
            mHandlerToEvent = handlerToEvent;
            mEventToHandlers = new HashMap<>();
            for (Map.Entry<MethodReference, Lifecycle.Event> entry : handlerToEvent.entrySet()) {
                Lifecycle.Event event = entry.getValue();
                List<MethodReference> methodReferences = mEventToHandlers.get(event);
                if (methodReferences == null) {
                    methodReferences = new ArrayList<>();
                    mEventToHandlers.put(event, methodReferences);
                }
                methodReferences.add(entry.getKey());
            }
        }

        /**
         * 回调生命周期方法
         *
         * @param source 事件源
         * @param event  事件
         * @param target 要被回调的订阅者
         */
        @SuppressWarnings("ConstantConditions")
        void invokeCallbacks(LifecycleOwner source, Lifecycle.Event event, Object target) {
            invokeMethodsForEvent(mEventToHandlers.get(event), source, event, target);
            invokeMethodsForEvent(mEventToHandlers.get(Lifecycle.Event.ON_ANY), source, event, target);
        }

        private static void invokeMethodsForEvent(List<MethodReference> handlers,
                                                  LifecycleOwner source,
                                                  Lifecycle.Event event,
                                                  Object mWrapped) {
            //遍历回调方法
            if (handlers != null) {
                for (int i = handlers.size() - 1; i >= 0; i--) {
                    handlers.get(i).invokeCallback(source, event, mWrapped);
                }
            }
        }
    }

    /**
     * 方法引用，处理方法调用
     */
    @SuppressWarnings("WeakerAccess")
    static class MethodReference {
        /**
         * 回调类型
         */
        final int mCallType;
        /**
         * 方法引用
         */
        final Method mMethod;

        MethodReference(int callType, Method method) {
            mCallType = callType;
            mMethod = method;
            //设置可访问，所以如果设置为private也可以调用
            mMethod.setAccessible(true);
        }

        /**
         * 反射回调方法
         */
        void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) {
            //noinspection TryWithIdenticalCatches
            //根据方法的形参进行回调
            try {
                switch (mCallType) {
                    case CALL_TYPE_NO_ARG:
                        mMethod.invoke(target);
                        break;
                    case CALL_TYPE_PROVIDER:
                        mMethod.invoke(target, source);
                        break;
                    case CALL_TYPE_PROVIDER_WITH_EVENT:
                        mMethod.invoke(target, source, event);
                        break;
                }
            } catch (InvocationTargetException e) {
                throw new RuntimeException("Failed to call observer method", e.getCause());
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            MethodReference that = (MethodReference) o;
            return mCallType == that.mCallType && mMethod.getName().equals(that.mMethod.getName());
        }

        @Override
        public int hashCode() {
            return 31 * mCallType + mMethod.getName().hashCode();
        }
    }
}